package fileCommodore.terminal;

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;

import javax.swing.*;

import de.mud.jta.*;
import de.mud.jta.event.*;
import de.mud.terminal.*;

/**
 * @author nado18@gmail.com, on Jul 28, 2007
 */
public class Moo
{
	private final static int debug = 0;
	
	private final static boolean personalJava = false;
	
	/** holds the last focussed plugin */
	private static Plugin focussedPlugin;
	
	/** holds the system clipboard or our own */
	private static Clipboard clipboard;
	
	private static String host, port;
	
	public static void main( String args[] )
	{
		final Properties options = new Properties();
		try
		{
			options.load( Main.class.getResourceAsStream( "/de/mud/jta/default.conf" ) );
		}
		catch (IOException e)
		{
			System.err.println( "kta: cannot load default.conf" );
		}
		catch (NullPointerException e)
		{
			System.err.println( "kta: cannot load default.conf" );
		}
		String error = parseOptions( options, args );
		
		if (error != null)
		{
			System.err.println( error );
			System.err.println( "usage: de.mud.jta.Main [-plugins pluginlist] "
					+ "[-addplugin plugin] " + "[-config url_or_file] "
					+ "[-term id] [host [port]]" );
			System.exit( 0 );
		}
		
		String cfg = options.getProperty( "Main.config" );
		if (cfg != null)
			try
			{
				options.load( new URL( cfg ).openStream() );
			}
			catch (IOException e)
			{
				try
				{
					options.load( new FileInputStream( cfg ) );
				}
				catch (Exception fe)
				{
					System.err.println( "kta: cannot load " + cfg );
				}
			}
		
		// configure the application and load all plugins
		
		 options.put( "plugins", "Shell,Terminal" );
		 options.put("Terminal.print.color", "true");
//		 options.put( "Shell.command", "/bin/bash" );
		
//		options.put( "plugins", "LocalProcess,Terminal" );
//		options.put( "LocalProcess.dir", "/tmp" );
//		// options.put( "LocalProcess.executable", "/usr/bin/man ls" );
//		options.put( "LocalProcess.executable", "man ls" );
		final Common setup = new Common( options );
		
		host = options.getProperty( "Socket.host" );
		if (host == null || host.trim().length() == 0)
			host = "localhost";
		else
			host = host.trim();
		port = options.getProperty( "Socket.port" );
		if (port == null || port.trim().length() == 0)
		{
			if (setup.getPlugins().containsKey( "SSH" )
					|| setup.getPlugins().containsKey( "SecondaryWindowSSH" )
					|| setup.getPlugins().containsKey( "JTAJSch" ))
			{
				port = "22";
			}
			else
			{
				port = "23";
			}
		}
		
		final JFrame frame =
				new JFrame( "kta: " + host
						+ ( port.equals( "23" ) ? "" : " " + port ) );
		
		// set up the clipboard
		try
		{
			clipboard = frame.getToolkit().getSystemClipboard();
		}
		catch (Exception e)
		{
			System.err.println( "kta: system clipboard access denied" );
			System.err.println( "kta: copy & paste only within the KTA" );
			clipboard = new Clipboard( "de.mud.jta.Main" );
		}
		
		setup.registerPluginListener( new OnlineStatusListener()
		{
			public void online()
			{
				frame.setTitle( "kta: " + host
						+ ( port.equals( "23" ) ? "" : " " + port ) );
			}
			
			public void offline()
			{
				frame.setTitle( "kta: offline" );
			}
		} );
		
		// register a focus status listener, so we know when a plugin got focus
		setup.registerPluginListener( new FocusStatusListener()
		{
			public void pluginGainedFocus( Plugin plugin )
			{
				if (debug > 0)
					System.err.println( "Main: " + plugin + " got focus" );
				focussedPlugin = plugin;
			}
			
			public void pluginLostFocus( Plugin plugin )
			{
				// we ignore the lost focus
				if (debug > 0)
					System.err.println( "Main: " + plugin + " lost focus" );
			}
		} );
		
		Map componentList = setup.getComponents();
		Iterator names = componentList.keySet().iterator();
		while (names.hasNext())
		{
			String name = (String) names.next();
			JComponent c = (JComponent) componentList.get( name );
			if (options.getProperty( "layout." + name ) == null)
			{
				System.err.println( "kta: no layout property set for '" + name
						+ "'" );
				frame.add( "South", c );
			}
			else
				frame.getContentPane().add(
					options.getProperty( "layout." + name ),
					c );
		}
		
		if (!personalJava)
		{
			
			frame.addWindowListener( new WindowAdapter()
			{
				public void windowClosing( WindowEvent evt )
				{
					setup.broadcast( new SocketRequest() );
					frame.setVisible( false );
					frame.dispose();
					System.exit( 0 );
				}
			} );
			
			// add a menu bar
			JMenuBar mb = new JMenuBar();
			JMenu file = new JMenu( "File" );
			file.setMnemonic( KeyEvent.VK_F );
			JMenuItem tmp;
			file.add( tmp = new JMenuItem( "Connect" ) );
			tmp.setAccelerator( KeyStroke.getKeyStroke(
				KeyEvent.VK_C,
				KeyEvent.SHIFT_MASK | KeyEvent.CTRL_MASK ) );
			tmp.addActionListener( new ActionListener()
			{
				public void actionPerformed( ActionEvent evt )
				{
					String destination =
							JOptionPane.showInputDialog(
								frame,
								new JLabel(
										"Enter your destination host (host[:port])" ),
								"Connect",
								JOptionPane.QUESTION_MESSAGE );
					if (destination != null)
					{
						int sep = 0;
						if (( sep = destination.indexOf( ' ' ) ) > 0
								|| ( sep = destination.indexOf( ':' ) ) > 0)
						{
							host = destination.substring( 0, sep );
							port = destination.substring( sep + 1 );
						}
						else
						{
							host = destination;
						}
						setup.broadcast( new SocketRequest() );
						setup.broadcast( new SocketRequest( host,
								Integer.parseInt( port ) ) );
					}
				}
			} );
			file.add( tmp = new JMenuItem( "Disconnect" ) );
			tmp.addActionListener( new ActionListener()
			{
				public void actionPerformed( ActionEvent evt )
				{
					setup.broadcast( new SocketRequest() );
				}
			} );
			file.addSeparator();
			if (setup.getComponents().get( "Terminal" ) != null)
			{
				file.add( tmp = new JMenuItem( "Print" ) );
				tmp.setAccelerator( KeyStroke.getKeyStroke(
					KeyEvent.VK_P,
					KeyEvent.CTRL_MASK ) );
				tmp.addActionListener( new ActionListener()
				{
					public void actionPerformed( ActionEvent evt )
					{
						PrintJob printJob =
								frame.getToolkit().getPrintJob(
									frame,
									"kta Terminal",
									null );
						// return if the user clicked cancel
						if (printJob == null)
							return;
						( (JComponent) setup.getComponents().get( "Terminal" ) ).print( printJob.getGraphics() );
						printJob.end();
					}
				} );
				file.addSeparator();
			}
			file.add( tmp = new JMenuItem( "Exit" ) );
			tmp.addActionListener( new ActionListener()
			{
				public void actionPerformed( ActionEvent evt )
				{
					frame.dispose();
					System.exit( 0 );
				}
			} );
			mb.add( file );
			
			JMenu edit = new JMenu( "Edit" );
			edit.add( tmp = new JMenuItem( "Copy" ) );
			tmp.setAccelerator( KeyStroke.getKeyStroke(
				KeyEvent.VK_C,
				KeyEvent.CTRL_MASK ) );
			tmp.addActionListener( new ActionListener()
			{
				public void actionPerformed( ActionEvent evt )
				{
					if (focussedPlugin instanceof VisualTransferPlugin)
						( (VisualTransferPlugin) focussedPlugin ).copy( clipboard );
				}
			} );
			edit.add( tmp = new JMenuItem( "Paste" ) );
			tmp.setAccelerator( KeyStroke.getKeyStroke(
				KeyEvent.VK_V,
				KeyEvent.CTRL_MASK ) );
			tmp.addActionListener( new ActionListener()
			{
				public void actionPerformed( ActionEvent evt )
				{
					if (focussedPlugin instanceof VisualTransferPlugin)
						( (VisualTransferPlugin) focussedPlugin ).paste( clipboard );
				}
			} );
			mb.add( edit );
			
			Map menuList = setup.getMenus();
			names = menuList.keySet().iterator();
			while (names.hasNext())
			{
				String name = (String) names.next();
				mb.add( (JMenu) menuList.get( name ) );
			}
			
			JMenu help = new JMenu( "Help" );
			help.setMnemonic( KeyEvent.VK_HELP );
			help.add( tmp = new JMenuItem( "General" ) );
			tmp.addActionListener( new ActionListener()
			{
				public void actionPerformed( ActionEvent e )
				{
					Help.show( frame, options.getProperty( "Help.url" ) );
				}
			} );
			mb.add( help );
			
			frame.setJMenuBar( mb );
			
		} // !personalJava
		
		frame.pack();
		
		if (( new Boolean( options.getProperty( "Applet.detach.fullscreen" ) ).booleanValue() ))
			frame.setSize( frame.getToolkit().getScreenSize() );
		else
			frame.pack();
		
		frame.setVisible( true );
		
		if (debug > 0)
			System.err.println( "host: '" + host + "', " + host.length() );
		if (host != null && host.length() > 0)
		{
			
			setup.broadcast( new SocketRequest( host, Integer.parseInt( port ) ) );
		}
		
		/* make sure the focus goes somewhere to start off with */
		setup.broadcast( new ReturnFocusRequest() );
	}
	
	/**
	 * Parse the command line argumens and override any standard options with
	 * the new values if applicable.
	 * <P>
	 * <SMALL> This method did not work with jdk 1.1.x as the setProperty()
	 * method is not available. So it uses now the put() method from Hashtable
	 * instead. </SMALL>
	 * 
	 * @param options
	 *            the original options
	 * @param args
	 *            the command line parameters
	 * @return a possible error message if problems occur
	 */
	private static String parseOptions( Properties options, String args[] )
	{
		boolean host = false, port = false;
		for (int n = 0; n < args.length; n++)
		{
			if (args[n].equals( "-config" ))
				if (!args[n + 1].startsWith( "-" ))
					options.put( "Main.config", args[++n] );
				else
					return "missing parameter for -config";
			else if (args[n].equals( "-plugins" ))
				if (!args[n + 1].startsWith( "-" ))
					options.put( "plugins", args[++n] );
				else
					return "missing parameter for -plugins";
			else if (args[n].equals( "-addplugin" ))
				if (!args[n + 1].startsWith( "-" ))
					options.put( "plugins", args[++n] + ","
							+ options.get( "plugins" ) );
				else
					return "missing parameter for -addplugin";
			else if (args[n].equals( "-term" ))
				if (!args[n + 1].startsWith( "-" ))
					options.put( "Terminal.id", args[++n] );
				else
					return "missing parameter for -term";
			else if (!host)
			{
				options.put( "Socket.host", args[n] );
				host = true;
			}
			else if (host && !port)
			{
				options.put( "Socket.port", args[n] );
				port = true;
			}
			else
				return "unknown parameter '" + args[n] + "'";
		}
		return null;
	}
}
